/**
 * @file bsp_lcd.c
 * @brief LCD initialize and basic operator.
 * @version 0.1
 * @date 2021-01-14
 *
 * @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
 *
 *      Licensed under the Apache License, Version 2.0 (the "License");
 *      you may not use this file except in compliance with the License.
 *      You may obtain a copy of the License at
 *
 *               http://www.apache.org/licenses/LICENSE-2.0
 *
 *      Unless required by applicable law or agreed to in writing, software
 *      distributed under the License is distributed on an "AS IS" BASIS,
 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *      See the License for the specific language governing permissions and
 *      limitations under the License.
 */

#include "bsp_lcd.h"

static const char *TAG = "bsp_lcd";

esp_lcd_panel_handle_t bsp_lcd_init(void)
{
    ESP_LOGI(TAG, "bsp_lcd_init start");
    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << GPIO_LCD_BL};
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));

    ESP_LOGI(TAG, "Install RGB LCD panel driver");
    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // RGB565 in parallel mode, thus 16bit in width
        .psram_trans_align = 64,
        .num_fbs = 2,
        // .bounce_buffer_size_px = 10 * LCD_WIDTH * 2,
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .disp_gpio_num = GPIO_NUM_NC,
        .pclk_gpio_num = GPIO_LCD_PCLK,
        .vsync_gpio_num = GPIO_LCD_VSYNC,
        .hsync_gpio_num = GPIO_LCD_HSYNC,
        .de_gpio_num = GPIO_LCD_DE,
        .data_gpio_nums = {
            GPIO_LCD_B0,
            GPIO_LCD_B1,
            GPIO_LCD_B2,
            GPIO_LCD_B3,
            GPIO_LCD_B4,
            GPIO_LCD_G0,
            GPIO_LCD_G1,
            GPIO_LCD_G2,
            GPIO_LCD_G3,
            GPIO_LCD_G4,
            GPIO_LCD_G5,
            GPIO_LCD_R0,
            GPIO_LCD_R1,
            GPIO_LCD_R2,
            GPIO_LCD_R3,
            GPIO_LCD_R4,
        },
        .timings = {
            .h_res = LCD_WIDTH, .v_res = LCD_HEIGHT,
    // The following parameters should refer to LCD spec
#if ((LCD_5r0_800x480 == 1) || (LCD_4r3_800x480 == 1))
            .pclk_hz = 15 * 1000 * 1000,
            .hsync_back_porch = 42,
            .hsync_front_porch = 20,
            .hsync_pulse_width = 1,
            .vsync_back_porch = 12,
            .vsync_front_porch = 4,
            .vsync_pulse_width = 10,
#elif (LCD_7r0_800x480 == 1)
            .pclk_hz = 15 * 1000 * 1000,
            .hsync_back_porch = 32,
            .hsync_front_porch = 10,
            .hsync_pulse_width = 16,
            .vsync_back_porch = 12,
            .vsync_front_porch = 15,
            .vsync_pulse_width = 3,
#elif (LCD_4r0_480x480 == 1)
            .pclk_hz = 10 * 1000 * 1000,
            .hsync_back_porch = 32,
            .hsync_front_porch = 10,
            .hsync_pulse_width = 16,
            .vsync_back_porch = 12,
            .vsync_front_porch = 15,
            .vsync_pulse_width = 3,
#elif (LCD_5r0_480x854 == 1) // EP5008S
            .pclk_hz = 12 * 1000 * 1000,
            .hsync_back_porch = 30,
            .hsync_front_porch = 12,
            .hsync_pulse_width = 6,
            .vsync_back_porch = 30,
            .vsync_front_porch = 12,
            .vsync_pulse_width = 1,
#elif (LCD_4r3_480x272 == 1)
            .pclk_hz = 10 * 1000 * 1000,
            .hsync_back_porch = 43,
            .hsync_front_porch = 75,
            .hsync_pulse_width = 4,
            .vsync_back_porch = 12,
            .vsync_front_porch = 8,
            .vsync_pulse_width = 4,
#endif

#if ((LCD_4r0_480x480 == 1) || (LCD_5r0_480x854 == 1)) // 时钟极性
            .flags.pclk_active_neg = false,            // true, // RGB data is clocked out on falling edge
#else
            .flags.pclk_active_neg = true,
#endif
        },
        .flags.fb_in_psram = true, // allocate frame buffer in PSRAM
    };
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

    /* Initialize RGB LCD panel */
    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));

    ESP_LOGI(TAG, "Turn on LCD backlight");
    gpio_set_level(GPIO_LCD_BL, 1);
    ESP_LOGI(TAG, "LCD resolution: %dx%d", LCD_WIDTH, LCD_HEIGHT);

    return panel_handle;
}


void bsp_lcd_flush(esp_lcd_panel_handle_t panel, int x, int y, int width, int height, uint16_t* pixels)
{
    esp_lcd_panel_draw_bitmap(panel, x, y, x + width, y + height, pixels);
}
